﻿namespace CodeSHARPer.ViewModel
{
    using CodeSHARPer.Services;
    using System;
    using System.Threading;
    using System.Windows;
    using System.Windows.Input;
    using System.Windows.Threading;

    internal partial class Workspace
    {
        private bool Closing_CanExecute()
        {
            if (this.shutDownInProgress == true)
                return false;

            // Check if conditions within the WorkspaceViewModel are suitable to close the application
            // eg.: Prompt to Cancel long running background tasks such as Search - Replace in Files (if any)

            return true;
        }

        /// <summary>
        /// Bind a window to some commands to be executed by the viewmodel.
        /// </summary>
        /// <param name="win"></param>
        public void InitCommandBinding(Window win)
        {
            this.InitEditCommandBinding(win);

            #region Zoom
            win.CommandBindings.Add(new CommandBinding(AppCommand.IncreaseFontSize,
                    (s, e) =>
                    {
                        this.ActiveDocument.FontSize++;
                    }));

            win.CommandBindings.Add(new CommandBinding(AppCommand.DecreaseFontSize,
                (s, e) =>
                {
                    this.ActiveDocument.FontSize--;
                }));

            win.CommandBindings.Add(new CommandBinding(AppCommand.NormalFontSize,
                (s, e) =>
                {
                    this.ActiveDocument.FontSize = this.Config.CodeEditorOptions.FontSize;
                })); 
            #endregion

            #region Exit
            win.CommandBindings.Add(new CommandBinding(AppCommand.Exit,
                (s, e) =>
                {
                    this.AppExit_CommandExecuted();
                }));
            #endregion Exit

            #region About
            win.CommandBindings.Add(new CommandBinding(AppCommand.About,
                (s, e) =>
                {
                    this.AppAbout_CommandExecuted();
                }));
            #endregion About

            #region Preferences
            win.CommandBindings.Add(new CommandBinding(AppCommand.Preferences,
                (s, e) =>
                {
                    this.AppPreferences_CommandExecuted();
                }));
            #endregion Preferences

            #region New
            win.CommandBindings.Add(new CommandBinding(ApplicationCommands.New,
                (s, e) =>
                {
                    if (e != null)
                        e.Handled = true;

                    this.OnNew();
                }));
            #endregion New

            #region Open
            win.CommandBindings.Add(new CommandBinding(ApplicationCommands.Open,
                (s, e) =>
                {
                    if (e != null)
                        e.Handled = true;

                    this.OnOpen();
                }));
            #endregion Open

            #region CloseFile
            // Closes the CodePadViewModel document supplied in e.parameter or the Active document
            win.CommandBindings.Add(new CommandBinding(AppCommand.CloseFile,
            (s, e) =>
            {
                try
                {
                    CodePadViewModel f = null;

                    if (e != null)
                    {
                        e.Handled = true;
                        f = e.Parameter as CodePadViewModel;
                    }

                    if (f != null)
                        this.Close(f);
                    else
                    {
                        if (this.ActiveDocument != null)
                            this.Close(this.ActiveDocument);
                    }
                }
                catch (Exception exp)
                {
                    logger.ErrorException(exp.Message, exp);
                    ServiceResolver.Instance.MessageBoxService.ShowError(exp.Message, App.IssueTrackerText);
                }
            }));
            #endregion CloseFile

            #region LoadFile
            win.CommandBindings.Add(new CommandBinding(AppCommand.LoadFile,
                (s, e) =>
                {
                    try
                    {
                        if (e == null)
                            return;

                        string filename = e.Parameter as string;

                        if (filename == null)
                            return;

                        this.Open(filename);
                    }
                    catch (Exception exp)
                    {
                        logger.ErrorException(exp.Message, exp);
                        ServiceResolver.Instance.MessageBoxService.ShowError(exp.Message, App.IssueTrackerText);
                    }
                }));
            #endregion LoadFile

            #region Save
            win.CommandBindings.Add(new CommandBinding(ApplicationCommands.Save,
                (s, e) =>
                {
                    try
                    {
                        if (e != null)
                            e.Handled = true;

                        if (this.ActiveDocument != null)
                            this.OnSave(this.ActiveDocument, false);
                    }
                    catch (Exception exp)
                    {
                        logger.ErrorException(exp.Message, exp);
                        ServiceResolver.Instance.MessageBoxService.ShowError(exp.Message, "Unhandled Error");
                    }
                },
                (s, e) =>
                {
                    if (e != null)
                    {
                        e.Handled = true;

                        if (this.ActiveDocument != null)
                            e.CanExecute = this.ActiveDocument.CanSave(null);
                    }
                }));
            #endregion Save

            #region SaveAs
            win.CommandBindings.Add(new CommandBinding(ApplicationCommands.SaveAs,
                (s, e) =>
                {
                    try
                    {
                        if (e != null)
                            e.Handled = true;

                        if (this.ActiveDocument != null)
                        {
                            if (this.ActiveDocument.DoSaveAs() == true)
                                this.Config.LastOpenedFiles.AddFileToList(this.ActiveDocument.FilePath);
                        }
                    }
                    catch (Exception exp)
                    {
                        logger.ErrorException(exp.Message, exp);
                        ServiceResolver.Instance.MessageBoxService.ShowError(exp.Message, App.IssueTrackerText);
                    }
                },
                (s, e) =>
                {
                    try
                    {
                        if (e != null)
                        {
                            e.Handled = true;
                            e.CanExecute = false;

                            if (this.ActiveDocument != null)
                                e.CanExecute = this.ActiveDocument.CanSaveAs();
                        }
                    }
                    catch (Exception exp)
                    {
                        logger.ErrorException(exp.Message, exp);
                        ServiceResolver.Instance.MessageBoxService.ShowError(exp.Message, App.IssueTrackerText);
                    }
                }));
            #endregion SaveAs

            #region SaveAll
            // Execute a command to save all Edited files and current program settings
            win.CommandBindings.Add(new CommandBinding(AppCommand.SaveAll,
            (s, e) =>
            {
                try
                {
                    // Save all Edited documents
                    if (this.openedFiles != null)               // Close all open files and make sure there are no unsaved Edits
                    {                                     // If there are any: Ask user if Edits should be saved
                        CodePadViewModel activeDoc = this.ActiveDocument;

                        try
                        {
                            for (int i = 0; i < this.openedFiles.Count; i++)
                            {
                                CodePadViewModel f = this.openedFiles[i];

                                if (f != null)
                                {
                                    if (f.IsDirty == true)
                                    {
                                        this.ActiveDocument = f;
                                        this.OnSave(f);
                                    }
                                }
                            }
                        }
                        catch (Exception exp)
                        {
                            ServiceResolver.Instance.MessageBoxService.ShowError(exp.Message, "An error occurred");
                        }
                        finally
                        {
                            if (activeDoc != null)
                                this.ActiveDocument = activeDoc;
                        }
                    }

                    // Save program settings
                    this.SaveConfigOnAppClosed();
                }
                catch (Exception exp)
                {
                    logger.ErrorException(exp.Message, exp);
                    ServiceResolver.Instance.MessageBoxService.ShowError(exp.Message, App.IssueTrackerText);
                }
            }));
            #endregion SaveAll

            #region RunCode
            win.CommandBindings.Add(new CommandBinding(AppCommand.RunCode,
                (s, e) =>
                {
                    try
                    {
                        CodePadViewModel activeDoc = this.ActiveDocument;

                        activeDoc.DoRunCommand(null);
                    }
                    catch (Exception exp)
                    {
                        logger.ErrorException(exp.Message, exp);
                        ServiceResolver.Instance.MessageBoxService.ShowError(exp.Message, App.IssueTrackerText);
                    }
                },
                (s, e) => { e.CanExecute = CanExecuteIfActiveDocumentIsFileViewModel(); }));
            #endregion RunCode

            #region Format
            win.CommandBindings.Add(new CommandBinding(AppCommand.FormatDocumentCode,
                (s, e) =>
                {
                    try
                    {
                        CodePadViewModel activeDoc = this.ActiveDocument;

                        activeDoc.DoFormatCommand(true);
                    }
                    catch (Exception exp)
                    {
                        logger.ErrorException(exp.Message, exp);
                        ServiceResolver.Instance.MessageBoxService.ShowError(exp.Message, App.IssueTrackerText);
                    }
                },
                (s, e) => { e.CanExecute = CanExecuteIfActiveDocumentIsFileViewModel(); }));

            win.CommandBindings.Add(new CommandBinding(AppCommand.FormatSelectionCode,
                (s, e) =>
                {
                    try
                    {
                        CodePadViewModel activeDoc = this.ActiveDocument;

                        activeDoc.DoFormatCommand(false);
                    }
                    catch (Exception exp)
                    {
                        logger.ErrorException(exp.Message, exp);
                        ServiceResolver.Instance.MessageBoxService.ShowError(exp.Message, App.IssueTrackerText);
                    }
                },
                (s, e) => { e.CanExecute = CanExecuteIfActiveDocumentIsFileViewModel(); }));
            #endregion

            #region ToogleToolbar
            //show/hide the toolbar
            win.CommandBindings.Add(new CommandBinding(AppCommand.ToogleToolbar,
                (s, e) => this.IsToolBarVisible = !this.IsToolBarVisible));
            #endregion ToogleToolbar

            #region ToogleOutput
            //show/hide the output panel
            win.CommandBindings.Add(new CommandBinding(AppCommand.ToogleOutput,
                (s, e) => this.ActiveDocument.IsOutputVisible = !this.ActiveDocument.IsOutputVisible));
            #endregion ToogleOutput
        }

        /// <summary>
        /// Set command bindings necessary to perform copy/cut/paste operations
        /// </summary>
        /// <param name="win"></param>
        public void InitEditCommandBinding(Window win)
        {
            #region GotoLine
            win.CommandBindings.Add(new CommandBinding(AppCommand.GotoLine,
            (s, e) =>
            {
                try
                {
                    e.Handled = true;

                    this.ShowGotoLineDialog();
                }
                catch (Exception exp)
                {
                    logger.ErrorException(exp.Message, exp);
                    ServiceResolver.Instance.MessageBoxService.ShowError(exp.Message, App.IssueTrackerText);
                }
            },
            (s, e) => { e.CanExecute = CanExecuteIfActiveDocumentIsFileViewModel(); }));
            #endregion GotoLine

            #region FindText
            win.CommandBindings.Add(new CommandBinding(AppCommand.FindText,
                (s, e) =>
                {
                    try
                    {
                        e.Handled = true;

                        this.ShowFindReplaceToolWindow();
                    }
                    catch (Exception exp)
                    {
                        logger.ErrorException(exp.Message, exp);
                        ServiceResolver.Instance.MessageBoxService.ShowError(exp.Message, App.IssueTrackerText);
                    }
                },
                (s, e) => { e.CanExecute = CanExecuteIfActiveDocumentIsFileViewModel(); }));
            #endregion FindText

            #region FindPreviousText
            win.CommandBindings.Add(new CommandBinding(AppCommand.FindPreviousText,
                (s, e) =>
                {
                    try
                    {
                        e.Handled = true;

                        CodePadViewModel f = this.ActiveDocument as CodePadViewModel;

                        if (f != null)
                        {
                            if (this.FindAndReplace != null)
                                this.FindAndReplace.FindNext(this.FindAndReplace, true);
                            else
                                this.ShowFindReplaceToolWindow();
                        }
                    }
                    catch (Exception exp)
                    {
                        logger.ErrorException(exp.Message, exp);
                        ServiceResolver.Instance.MessageBoxService.ShowError(exp.Message, App.IssueTrackerText);
                    }
                },
                (s, e) => { e.CanExecute = CanExecuteIfActiveDocumentIsFileViewModel(); }));
            #endregion FindPreviousText

            #region FindNextText
            win.CommandBindings.Add(new CommandBinding(AppCommand.FindNextText,
                (s, e) =>
                {
                    try
                    {
                        e.Handled = true;

                        CodePadViewModel f = this.ActiveDocument as CodePadViewModel;

                        if (f != null)
                        {
                            if (this.FindAndReplace != null)
                            {
                                SetFindNextAction();
                                SetFindAndReplaceEditor(f);
                                this.FindAndReplace.FindNext(this.FindAndReplace, false);
                            }
                            else
                                this.ShowFindReplaceToolWindow();
                        }
                    }
                    catch (Exception exp)
                    {
                        logger.ErrorException(exp.Message, exp);
                        ServiceResolver.Instance.MessageBoxService.ShowError(exp.Message, App.IssueTrackerText);
                    }
                },
                (s, e) => { e.CanExecute = CanExecuteIfActiveDocumentIsFileViewModel(); }));
            #endregion FindNextText

            #region ReplaceText
            win.CommandBindings.Add(new CommandBinding(AppCommand.ReplaceText,
                (s, e) =>
                {
                    try
                    {
                        e.Handled = true;

                        this.ShowFindReplaceToolWindow(false);
                    }
                    catch (Exception exp)
                    {
                        logger.ErrorException(exp.Message, exp);
                        ServiceResolver.Instance.MessageBoxService.ShowError(exp.Message, App.IssueTrackerText);
                    }
                },
                (s, e) => { e.CanExecute = CanExecuteIfActiveDocumentIsFileViewModel(); }));
            #endregion ReplaceText

            #region References
            win.CommandBindings.Add(new CommandBinding(AppCommand.References,
               (s, e) =>
               {
                   this.AppReferences_CommandExecuted();
               },
                (s, e) => { e.CanExecute = CanExecuteIfActiveDocumentIsFileViewModel(); }));
            #endregion References
        }

        private bool CanExecuteIfActiveDocumentIsFileViewModel()
        {
            return this.ActiveDocument != null && this.ActiveDocument is CodePadViewModel;
        }
    }
}
